#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#define MAX_UNICODE 0x10FFFF
uint32_t gbt[MAX_UNICODE + 1]; // 增加一个额外的元素以确保索引安全

// 加载映射表
//GB18030-2022与UCS代码映射表
//http://nits.org.cn/index/article/4034
int load_mapping_table(const char* file)
{
    FILE* fp = fopen(file, "r");
    if (!fp)
    {
        perror(file);
        return -1;
    }

    uint32_t unicode, gbcode;

    while (fscanf(fp, "%x %x\n", &unicode, &gbcode) != EOF)
    {
        if (unicode > MAX_UNICODE)
        {
            printf("invalid mapping: %x %x\n", unicode, gbcode);
            continue;
        }
        gbt[unicode] = gbcode;
    }

    fclose(fp);

    return 0;
}

// 将映射表保存到文件
int dump_mapping_table(const char* file)
{
    FILE* fp = fopen(file, "wb");
    if (!fp)
    {
        perror(file);
        return -1;
    }

    fwrite(&gbt, sizeof(gbt), 1, fp);
    fclose(fp);
    return 0;
}

// 从文件流中读取一个UTF8字符并转为UTF32
// 成功返回UTF32编码，失败返回EOF
int utf8_to_utf32(FILE* fp)
{
    int code_point = 0;
    int byte;
    int bytes_read = 0;
    int bytes_expected = 0;

    // 读取第一个字节
    byte = fgetc(fp);
    if (byte == EOF) {
        return EOF; // 文件结束或读取失败
    }

    // 确定UTF-8字符的长度
    if ((byte & 0x80) == 0) {  // 1字节字符
        code_point = byte;
        return code_point;
    } else if ((byte & 0xE0) == 0xC0) {  // 2字节字符
        bytes_expected = 2;
    } else if ((byte & 0xF0) == 0xE0) {  // 3字节字符
        bytes_expected = 3;
    } else if ((byte & 0xF8) == 0xF0) {  // 4字节字符
        bytes_expected = 4;
    } else {
        fprintf(stderr, "invalid UTF-8: %x\n", byte);
        return EOF; // 无效的UTF-8序列
    }

    // 解码UTF-8字符
    code_point = (byte & ((1 << (8 - bytes_expected)) - 1));  // 移除前导1
    bytes_read = 1;

    while (bytes_read < bytes_expected) {
        byte = fgetc(fp);
        if (byte == EOF || (byte & 0xC0) != 0x80) {  // 检查是否为有效的后续字节
            fprintf(stderr, "invalid UTF-8 continuation byte: %x\n", byte);
            return EOF; // 无效的UTF-8序列或文件结束
        }
        code_point = (code_point << 6) | (byte & 0x3F);
        bytes_read++;
    }

    return code_point;
}

// 将UTF8编码转为GB18030
int main(int argc, char** argv)
{
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <input_file> <output_file>\n", argv[0]);
        return 1;
    }

    // 加载基本平面映射表
    if (load_mapping_table("GB18030-2022MappingTableBMP.txt")) {
        fprintf(stderr, "Failed to load mapping table BMP.\n");
        return 1;
    }

    // 加载补充平面映射表
    if (load_mapping_table("GB18030-2022MappingTableSMP.txt")) {
        fprintf(stderr, "Failed to load mapping table SMP.\n");
        return 1;
    }

    dump_mapping_table("gb18030.bin");

    // 打开输入文件
    FILE* fp = fopen(argv[1], "rb");
    if (!fp)
    {
        perror(argv[1]);
        return -1;
    }

    // 打开输出文件
    FILE* fpout = fopen(argv[2], "wb");
    if (!fpout)
    {
        fpout = stdout;
    }

    // 读取输入文件并转换
    int unicode;
    while ((unicode = utf8_to_utf32(fp)) != EOF)
    {
        uint32_t gbcode = gbt[unicode];
        // 判断编码长度
        if (gbcode < 0x80)
        {
            // 单字节编码，输出1个字节
            fputc((gbcode >>  0) & 0xff, fpout);
        }
        else if (gbcode < 0xff00)
        {
            // 双字节编码，输出2个字节
            fputc((gbcode >>  8) & 0xff, fpout);
            fputc((gbcode >>  0) & 0xff, fpout);
        }
        else
        {
            // 4字节编码，输出4个字节
            fputc((gbcode >> 24) & 0xff, fpout);
            fputc((gbcode >> 16) & 0xff, fpout);
            fputc((gbcode >>  8) & 0xff, fpout);
            fputc((gbcode >>  0) & 0xff, fpout);
        }
    }

    // 关闭输入文件
    fclose(fp);

    // 关闭输出文件
    if (fpout != stdout)
    {
        fclose(fpout);
    }

    return 0;
}
